package demoMod.anm2editor.ui;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.math.Interpolation;
import demoMod.anm2editor.enums.CustomPathType;
import demoMod.anm2editor.fonts.FontKeys;
import demoMod.anm2editor.interfaces.ReloadStringsSubscriber;
import demoMod.anm2editor.localization.LocalizedStrings;
import demoMod.anm2editor.model.*;
import demoMod.anm2editor.utils.Preferences;
import demoMod.gdxform.core.FormManager;
import demoMod.gdxform.enums.GFrameCloseStrategy;
import demoMod.gdxform.enums.GFrameWindowMode;
import demoMod.gdxform.enums.GFrameWindowStyle;
import demoMod.gdxform.helpers.FontHelper;
import demoMod.gdxform.ui.GButton;
import demoMod.gdxform.ui.GFrame;
import demoMod.gdxform.ui.GLabel;

import java.util.ArrayList;
import java.util.List;

public class PathEditWindow extends GFrame implements ReloadStringsSubscriber {
    public static final String ID = "PathEditWindow";
    private final HistoryPanel historyPanel;
    private final KeyFrame frameToBake;
    private final Track track;
    private KeyFrame nextFrame;
    private final List<KeyFrame> bakedFrames = new ArrayList<>();
    private Interpolation progressCurve = new Interpolation() {
        @Override
        public float apply(float a) {
            return 0;
        }
    };
    private final PathCurve pathCurve;
    private boolean confirmed = false;

    public PathEditWindow(BitmapFont bannerFont, KeyFrame frameToBake) {
        super(Gdx.graphics.getWidth() / 2.0F - Gdx.graphics.getWidth() * 0.1F, Gdx.graphics.getHeight() * 0.4F, Gdx.graphics.getWidth() * 0.2F, Gdx.graphics.getHeight() * 0.2F, bannerFont, GFrameWindowStyle.CLOSE_BUTTON_ONLY, false);
        setWindowMode(GFrameWindowMode.NON_MODAL);
        setId(ID);
        this.frameToBake = frameToBake;
        Timeline timeline = ((Timeline) FormManager.getInstance().getContainerById(Timeline.ID));
        track = timeline.getCurrentSelectedTrack();
        List<KeyFrame> keyFrames = track.getContent(Project.currentProject.getCurrentAnimation().getName()).getKeyFrames();
        List<KeyFrame> originalKeyFrames = new ArrayList<>(keyFrames);
        for (KeyFrame keyFrame : keyFrames) {
            if (keyFrame == frameToBake) {
                int index = keyFrames.indexOf(keyFrame);
                if (keyFrames.size() - 1 == index) {
                    nextFrame = frameToBake.makeCopy();
                } else {
                    nextFrame = keyFrames.get(index + 1);
                }
                break;
            }
        }

        for (int i=0;i<frameToBake.delay;i++) {
            KeyFrame frame = frameToBake.makeCopy();
            frame.delay = 1;
            frame.interpolated = true;
            bakedFrames.add(frame);
        }

        if (!bakedFrames.isEmpty()) {
            bakedFrames.set(bakedFrames.size() - 1, nextFrame.makeCopy());
            bakedFrames.get(bakedFrames.size() - 1).delay = 1;
        }

        int index = keyFrames.indexOf(frameToBake);
        int startIndex = track.getContent(Project.currentProject.getCurrentAnimation().getName()).getKeyframeStartIndex(frameToBake);
        keyFrames.remove(frameToBake);
        keyFrames.addAll(index, bakedFrames);

        List<String> strings = LocalizedStrings.getStrings("PathEditWindow");
        setTitle(strings.get(0) + " - " + startIndex + " ~ " + (startIndex + frameToBake.delay));
        setResizable(false);
        setCloseStrategy(GFrameCloseStrategy.EXIT_ON_CLOSE);
        LocalizedStrings.subscribe(this);
        historyPanel = (HistoryPanel) FormManager.getInstance().getContainerById(HistoryPanel.ID);

        GButton confirm = new GButton(3, 0.03F * getHeight(), getWidth() * 0.15F, 20, FontHelper.getFont(FontKeys.SIM_HEI_14)) {
            @Override
            public void onClick() {
                confirmed = true;
                FormManager.getInstance().removeContainer(PathEditWindow.this);
            }
        };
        confirm.setText(strings.get(1));
        confirm.setBackground(new Color(0, 47.0F / 255.0F, 147.0F / 255.0F, 1.0F));
        confirm.setBorderWidth(2);
        confirm.setBorder(Color.LIGHT_GRAY.cpy());
        GButton cancel = new GButton(3 + getWidth() * 0.2F, 0.03F * getHeight(), getWidth() * 0.15F, 20, FontHelper.getFont(FontKeys.SIM_HEI_14)) {
            @Override
            public void onClick() {
                FormManager.getInstance().removeContainer(PathEditWindow.this);
            }
        };
        cancel.setText(strings.get(2));
        cancel.setBackground(Color.LIGHT_GRAY.cpy());
        cancel.setBorderWidth(2);
        cancel.setBorder(Color.LIGHT_GRAY.cpy());

        addElement(confirm);
        addElement(cancel);

        int totalDelay = 0;
        for (int i=0;i<index;i++) {
            totalDelay += keyFrames.get(i).delay;
        }
        final int startFrameIndex = totalDelay;
        final int endFrameIndex = startFrameIndex + bakedFrames.size();

        GButton preview = new GButton(3, 0.03F * getHeight() + 35, getWidth() * 0.15F, 20, FontHelper.getFont(FontKeys.SIM_HEI_14)) {
            @Override
            public void onClick() {
                if (timeline.isPlaying()) {
                    timeline.pause();
                    timeline.setPointerIndex(startFrameIndex);
                } else {
                    timeline.play();
                }
            }

            @Override
            public void update() {
                super.update();
                if (FormManager.getInstance().getEventHooks().getCurrentFocusedElement() != PathEditWindow.this) {
                    return;
                }
                if (timeline.getPointerIndex() > endFrameIndex || timeline.getPointerIndex() < startFrameIndex) {
                    timeline.setPointerIndex(startFrameIndex);
                }
            }
        };
        preview.setText(strings.get(3));
        preview.setBackground(new Color(0, 47.0F / 255.0F, 147.0F / 255.0F, 1.0F));
        preview.setBorderWidth(2);
        preview.setBorder(Color.LIGHT_GRAY.cpy());

        addElement(preview);

        PreviewPane previewPane = (PreviewPane) FormManager.getInstance().getContainerById(PreviewPane.ID);
        GButton addAnchor = new GButton(3, getHeight() * 0.5F - 10, getWidth() * 0.2F, 20, FontHelper.getFont(FontKeys.SIM_HEI_14)) {
            @Override
            public void onClick() {
                List<Anchor> anchors = previewPane.getPathCurve().getAnchors();
                Anchor anchor = new Anchor();
                anchor.setX((anchors.get(anchors.size() - 2).getX() + anchors.get(anchors.size() - 1).getX()) / 2.0F);
                anchor.setY((anchors.get(anchors.size() - 2).getY() + anchors.get(anchors.size() - 1).getY()) / 2.0F);
                anchor.setBezierPoints(new ArrayList<>());

                Anchor guideAnchor1 = new Anchor();
                guideAnchor1.setX(anchor.getX() + 15.0F);
                guideAnchor1.setY(anchor.getY());

                Anchor guideAnchor2 = new Anchor();
                guideAnchor2.setX(anchor.getX() - 15.0F);
                guideAnchor2.setY(anchor.getY());

                anchor.getBezierPoints().add(guideAnchor1);
                anchor.getBezierPoints().add(guideAnchor2);
                previewPane.getPathCurve().addAnchor(anchor);
                previewPane.setCurrentSelectedAnchor(anchor);
                previewPane.clearPathCache();
            }
        };
        addAnchor.setText(strings.get(4));
        addAnchor.setBackground(new Color(0, 47.0F / 255.0F, 147.0F / 255.0F, 1.0F));
        addAnchor.setBorderWidth(2);
        addAnchor.setBorder(Color.LIGHT_GRAY.cpy());

        addElement(addAnchor);

        GButton delAnchor = new GButton(addAnchor.getX(false) + addAnchor.getWidth() + 9, getHeight() * 0.5F - 10, getWidth() * 0.2F, 20, FontHelper.getFont(FontKeys.SIM_HEI_14)) {
            @Override
            public void onClick() {
                if (previewPane.getCurrentSelectedAnchor() != null) {
                    previewPane.getPathCurve().removeAnchor(previewPane.getCurrentSelectedAnchor());
                    previewPane.setCurrentSelectedAnchor(null);
                    previewPane.clearPathCache();
                }
            }
        };
        delAnchor.setText(strings.get(5));
        delAnchor.setBackground(new Color(0, 47.0F / 255.0F, 147.0F / 255.0F, 1.0F));
        delAnchor.setBorderWidth(2);
        delAnchor.setBorder(Color.LIGHT_GRAY.cpy());

        addElement(delAnchor);

        GButton anchorType = new GButton(delAnchor.getX(false) + delAnchor.getWidth() + 9, getHeight() * 0.5F - 10, getWidth() * 0.2F, 20, FontHelper.getFont(FontKeys.SIM_HEI_14)) {
            @Override
            public void onClick() {
                List<String> options = new ArrayList<>();
                options.add(strings.get(7));
                options.add(strings.get(8));
                OptionWindow optionWindow = new OptionWindow(strings.get(6), options, bannerFont, 0);
                optionWindow.setConfirmCallback(index -> {
                    if (index == 0) {
                        pathCurve.setPathType(CustomPathType.BROKEN_LINE);
                    } else {
                        pathCurve.setPathType(CustomPathType.PEN);
                    }
                    previewPane.clearPathCache();
                });
            }
        };
        anchorType.setText(strings.get(6));
        anchorType.setBackground(new Color(0, 47.0F / 255.0F, 147.0F / 255.0F, 1.0F));
        anchorType.setBorderWidth(2);
        anchorType.setBorder(Color.LIGHT_GRAY.cpy());

        addElement(anchorType);

        GLabel lProgress = new GLabel(anchorType.getX(false) + anchorType.getWidth(), getHeight() * 0.75F, getWidth(), getHeight() * 0.07F, FontHelper.getFont(FontKeys.SIM_HEI_14));
        lProgress.setText(strings.get(9));
        addElement(lProgress);

        GButton progressCurve = new GButton(anchorType.getX(false) + anchorType.getWidth() + getWidth() * 0.05F, getHeight() * 0.5F - getWidth() * 0.1F, getWidth() * 0.2F, getWidth() * 0.2F, FontHelper.getFont(FontKeys.SIM_HEI_14)) {
            @Override
            public void onClick() {
                previewPane.setProgressCurve(PathEditWindow.this.progressCurve);
                new CurveEditWindow(frameToBake, bakedFrames, originalKeyFrames, PathEditWindow.this.progressCurve, interpolation -> {
                    previewPane.setProgressCurve(interpolation);
                    PathEditWindow.this.progressCurve = interpolation;
                });
            }
        };
        progressCurve.setFgTexture(new Texture("buttons/reset_activated.png"));
        progressCurve.setId("progressCurve");
        progressCurve.setText("");

        addElement(progressCurve);

        Preferences.getPreferences().setPathEditMode(true);
        pathCurve = new PathCurve();
        pathCurve.setPathType(CustomPathType.BROKEN_LINE);
        Anchor start = new Anchor();
        start.setX(frameToBake.xPosition);
        start.setY(-frameToBake.yPosition);
        start.setBezierPoints(new ArrayList<>());
        Anchor guideAnchor1 = new Anchor();
        guideAnchor1.setX(start.getX() + 15.0F);
        guideAnchor1.setY(start.getY());
        start.getBezierPoints().add(guideAnchor1);
        Anchor end = new Anchor();
        KeyFrame endFrame = bakedFrames.isEmpty() ? frameToBake : nextFrame;
        end.setX(endFrame.xPosition);
        end.setY(-endFrame.yPosition);
        end.setBezierPoints(new ArrayList<>());
        Anchor guideAnchor2 = new Anchor();
        guideAnchor2.setX(end.getX() - 15.0F);
        guideAnchor2.setY(end.getY());
        end.getBezierPoints().add(guideAnchor2);
        pathCurve.setStartingAnchor(start);
        pathCurve.setEndingAnchor(end);
        previewPane.clearPathCache();
        previewPane.setPathCurve(pathCurve);
        previewPane.setBakedFrames(bakedFrames);
    }

    @Override
    public void activate() {
        PreviewPane previewPane = (PreviewPane) FormManager.getInstance().getContainerById(PreviewPane.ID);
        previewPane.clearPathCache();
        previewPane.setPathCurve(pathCurve);
        previewPane.setBakedFrames(bakedFrames);
    }

    @Override
    public void dispose() {
        super.dispose();
        if (!confirmed) {
            cancelChange();
        } else {
            Operation operation = new Operation() {
                @Override
                public void undo() {
                    cancelChange();
                }

                @Override
                public void redo() {
                    List<KeyFrame> keyFrames = track.getContent(Project.currentProject.getCurrentAnimation().getName()).getKeyFrames();
                    for (KeyFrame keyFrame : keyFrames) {
                        if (keyFrame == frameToBake) {
                            int index = keyFrames.indexOf(keyFrame);
                            if (keyFrames.size() - 1 == index) {
                                nextFrame = frameToBake.makeCopy();
                            } else {
                                nextFrame = keyFrames.get(index + 1);
                            }
                            break;
                        }
                    }

                    int index = keyFrames.indexOf(frameToBake);
                    keyFrames.remove(frameToBake);
                    keyFrames.addAll(index, bakedFrames);
                }
            };
            List<String> strings = LocalizedStrings.getStrings("PathEditWindow");
            operation.setName(strings.get(0));
            historyPanel.addOperation(operation);
        }
        LocalizedStrings.unsubscribe(this);
        Preferences.getPreferences().setPathEditMode(FormManager.getInstance().getContainerById(ID) != null);
    }

    private void cancelChange() {
        List<KeyFrame> keyFrames = track.getContent(Project.currentProject.getCurrentAnimation().getName()).getKeyFrames();
        int index = keyFrames.indexOf(bakedFrames.get(0));
        keyFrames.removeAll(bakedFrames);
        keyFrames.add(index, frameToBake);
    }

    @Override
    public void onReloadStrings() {

    }
}
